//   Copyright 2012,2013 Vaughn Vernon
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
package com.saasovation.agilepm.domain.model;

import com.saasovation.agilepm.AgilePmAppTest;
import com.saasovation.agilepm.domain.model.product.ProductRepository;
import com.saasovation.agilepm.domain.model.team.ProductOwnerRepository;
import com.saasovation.agilepm.domain.model.team.TeamMemberRepository;
import com.saasovation.agilepm.domain.model.team.TeamRepository;
import com.saasovation.agilepm.port.adapter.persistence.LevelDBDatabasePath;
import com.saasovation.agilepm.port.adapter.spring.RabbitEventTrackingConfiguration;
import com.saasovation.common.TestBase;
import com.saasovation.common.annotation.TestContainers;
import com.saasovation.common.domain.model.DomainEvent;
import com.saasovation.common.domain.model.DomainEventPublisher;
import com.saasovation.common.domain.model.DomainEventSubscriber;
import com.saasovation.common.domain.model.EventTracking;
import com.saasovation.common.port.adapter.persistence.leveldb.LevelDBProvider;
import com.saasovation.common.port.adapter.persistence.leveldb.LevelDBUnitOfWork;
import org.iq80.leveldb.DB;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;

import java.util.ArrayList;
import java.util.HashMap;

import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;

@SpringBootTest(classes = AgilePmAppTest.class, webEnvironment = RANDOM_PORT)
@TestContainers(use = true)
@ActiveProfiles("test")
@Import(RabbitEventTrackingConfiguration.class)
public abstract class DomainTestBase extends TestBase {
    protected DB database;
    @Autowired
    protected ProductOwnerRepository productOwnerRepository;
    @Autowired
    protected ProductRepository productRepository;
    @Autowired
    protected TeamMemberRepository teamMemberRepository;
    @Autowired
    protected TeamRepository teamRepository;
    @Autowired
    protected EventTracking eventTracking;

    @DynamicPropertySource
    public static void dataSourceProperties(DynamicPropertyRegistry registry) {
        if (!useTestContainers(DomainTestBase.class)) {
            return;
        }
        initRabbitMqContainer(registry);
    }

    public DomainTestBase() {
        super();
    }

    @BeforeEach
    protected void setUp() {
        DomainEventPublisher.instance().reset();
        DomainEventPublisher.instance().subscribe(new DomainEventSubscriber<>() {
            @Override
            public void handleEvent(DomainEvent aDomainEvent) {
                eventTracking.handledEvents().add(aDomainEvent.getClass());
            }

            @Override
            public Class<DomainEvent> subscribedToEventType() {
                return DomainEvent.class;
            }
        });
        this.database = LevelDBProvider.instance()
                .databaseFrom(LevelDBDatabasePath.agilePMPath());
        LevelDBProvider.instance().purge(this.database);
        LevelDBUnitOfWork.start(this.database);

        this.eventTracking.setHandledEvents(new ArrayList<>());
        this.eventTracking.setHandledNotifications(new HashMap<>());
    }


    @AfterEach
    protected void tearDown() {
        LevelDBProvider.instance().purge(this.database);
    }
}
